home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 24 / CU Amiga Magazine's Super CD-ROM 24 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-07].iso / CUCD / Programming / SWI / source / src / pl-stream.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-15  |  27.8 KB  |  1,633 lines

  1. /*  $Id: pl-stream.c,v 1.23 1998/04/15 15:17:08 jan Exp $
  2.  
  3.     Copyright (c) 1990 Jan Wielemaker. All rights reserved.
  4.     See ../LICENCE to find out about your rights.
  5.     jan@swi.psy.uva.nl
  6.  
  7.     Purpose: SWI-Prolog IO streams
  8. */
  9.  
  10. #ifdef __WIN32__
  11. #include <uxnt.h>
  12. #define MD "config/win32.h"
  13. #endif
  14.  
  15. #ifdef MD
  16. #include MD
  17. #else
  18. #include "config.h"
  19. #endif
  20.  
  21. #define PL_KERNEL 1
  22. #include "pl-stream.h"
  23. #include <sys/types.h>
  24. #include <errno.h>
  25. #ifdef HAVE_MALLOC_H
  26. #include <malloc.h>
  27. #endif
  28. #include <memory.h>
  29. #include <string.h>
  30. #include <fcntl.h>
  31. #include <stdlib.h>
  32. #include <stdarg.h>
  33. #include <ctype.h>
  34. #ifdef HAVE_UNISTD_H
  35. #include <unistd.h>
  36. #endif
  37. #include <stdio.h>            /* sprintf() for numeric values */
  38. #include <assert.h>
  39. #ifdef SYSLIB_H
  40. #include SYSLIB_H
  41. #endif
  42.  
  43. #ifndef FALSE
  44. #define FALSE 0
  45. #endif
  46. #ifndef TRUE
  47. #define TRUE 1
  48. #endif
  49.  
  50. #define char_to_int(c)    (0xff & (int)(c))
  51.  
  52. #define TMPBUFSIZE 256            /* Serror bufsize for Svfprintf() */
  53.  
  54. int Slinesize = SIO_LINESIZE;        /* Sgets() buffer size */
  55.  
  56. static int    S__flushbuf(IOSTREAM *s);
  57.  
  58. #define S__fupdatefilepos(s, c) S___fupdatefilepos(s, c)
  59.  
  60.          /*******************************
  61.          *          BUFFER        *
  62.          *******************************/
  63.  
  64. static int
  65. S__setbuf(IOSTREAM *s, char *buffer, int size)
  66. { if ( size == 0 )
  67.     size = SIO_BUFSIZE;
  68.  
  69.   s->bufsize = size;
  70.   
  71.   if ( s->buffer && !(s->flags & SIO_USERBUF) )
  72.     free(s->buffer);
  73.  
  74.   if ( buffer )
  75.   { s->buffer = buffer;
  76.     s->flags |= SIO_USERBUF;
  77.   } else
  78.   { if ( !(s->buffer = malloc(s->bufsize)) )
  79.     { errno = ENOMEM;
  80.       return -1;
  81.     }
  82.     s->flags &= ~SIO_USERBUF;
  83.   }
  84.  
  85.   s->unbuffer = s->buffer;
  86.   s->limitp   = &s->buffer[s->bufsize];
  87.   s->bufp     = s->buffer;
  88.  
  89.   return s->bufsize;
  90. }
  91.  
  92.  
  93. static int
  94. S__removebuf(IOSTREAM *s)
  95. { if ( s->buffer )
  96.   { int rval = S__flushbuf(s);
  97.  
  98.     if ( !(s->flags & SIO_USERBUF) )
  99.       free(s->buffer);
  100.     s->bufp = s->limitp = s->buffer = NULL;
  101.     s->bufsize = 0;
  102.  
  103.     return rval;
  104.   }
  105.  
  106.   return 0;
  107. }
  108.  
  109.  
  110. int
  111. Slock(IOSTREAM *s)
  112. { if ( s->locks )
  113.     s->locks++;
  114.   else if ( s->flags & SIO_NBUF )
  115.   { s->locks = 1;
  116.     return S__setbuf(s, NULL, TMPBUFSIZE);
  117.   }
  118.  
  119.   return 0;
  120. }
  121.  
  122.  
  123. int
  124. Sunlock(IOSTREAM *s)
  125. { if ( s->locks )
  126.   { if ( --s->locks == 0 )
  127.       return S__removebuf(s);
  128.   }
  129.  
  130.   return 0;
  131. }
  132.  
  133.          /*******************************
  134.          *         FLUSH/FILL        *
  135.          *******************************/
  136.  
  137. static int
  138. S__flushbuf(IOSTREAM *s)
  139. { int size = s->bufp - s->buffer;
  140.  
  141.   if ( (*s->functions->write)(s->handle, s->buffer, size) != size )
  142.     return -1;
  143.  
  144.   s->bufp = s->buffer;
  145.  
  146.   return size;
  147. }
  148.  
  149.  
  150. static int
  151. S__flushbufc(int c, IOSTREAM *s)
  152. { if ( s->buffer )
  153.   { if ( S__flushbuf(s) < 0 )
  154.       return -1;
  155.  
  156.     *s->bufp++ = (c & 0xff);
  157.   } else
  158.   { if ( s->flags & SIO_NBUF )
  159.     { char chr = (char)c;
  160.     
  161.       if ( (*s->functions->write)(s->handle, &chr, 1) != 1 )
  162.     return -1;
  163.     } else
  164.     { if ( S__setbuf(s, NULL, 0) < 0 )
  165.     return -1;
  166.       *s->bufp++ = (char)c;
  167.     }
  168.   }
  169.  
  170.   return c;
  171. }
  172.  
  173.  
  174. #define ReadF(s) (s)->functions->read
  175.  
  176. int
  177. S__fillbuf(IOSTREAM *s)
  178. { if ( s->flags & (SIO_FEOF|SIO_FERR) )
  179.   { s->flags |= SIO_FEOF2;        /* reading past eof */
  180.     return -1;
  181.   }
  182.  
  183.   if ( s->flags & SIO_NBUF )
  184.   { char chr;
  185.     int n;
  186.  
  187.     if ( (n=(*ReadF(s))(s->handle, &chr, 1)) == 1 )
  188.     { return char_to_int(chr);
  189.     } else if ( n == 0 )
  190.     { if ( !(s->flags & SIO_NOFEOF) )
  191.     s->flags |= SIO_FEOF;
  192.       return EOF;
  193.     } else
  194.     { s->flags |= SIO_FERR;
  195.       return -1;            /* error */
  196.     }
  197.   } else
  198.   { int n;
  199.  
  200.     if ( !s->buffer )
  201.     { if ( S__setbuf(s, NULL, 0) < 0 )
  202.     return -1;
  203.       s->limitp = s->buffer;
  204.     }
  205.  
  206.     if ( (n=(*ReadF(s))(s->handle, s->buffer, s->bufsize)) > 0 )
  207.     { s->bufp = s->buffer;
  208.       s->limitp = &s->buffer[n];
  209.       return char_to_int(*s->bufp++);
  210.     } else
  211.     { s->bufp = s->buffer;        /* empty the buffer */
  212.       s->limitp = s->buffer;
  213.  
  214.       if ( n == 0 )
  215.       { if ( !(s->flags & SIO_NOFEOF) )
  216.       s->flags |= SIO_FEOF;
  217.     return EOF;
  218.       } else
  219.       { s->flags |= SIO_FERR;
  220.     return -1;
  221.       }
  222.     }
  223.   }
  224. }
  225.  
  226.          /*******************************
  227.          *       CHARACTER I/O    *
  228.          *******************************/
  229.  
  230.  
  231. inline int
  232. S___fupdatefilepos(IOPOS *p, int c)
  233. { if ( p )
  234.   { switch(c)
  235.     { case '\n':
  236.     p->lineno++;
  237.         p->linepos = 0;
  238. /*      p->flags &= ~SIO_NOLINEPOS; TBD*/
  239.         break;
  240.       case '\r':
  241.     p->linepos = 0;
  242.     break;
  243.       case '\b':
  244.     if ( p->linepos > 0 )
  245.       p->linepos--;
  246.     break;
  247.       case EOF:
  248.     return c;
  249.       case '\t':
  250.     p->linepos |= 7;
  251.       default:
  252.     p->linepos++;
  253.     }
  254.   
  255.     p->charno++;
  256.   }
  257.  
  258.   return c;
  259. }
  260.  
  261. int
  262. Sputc(int c, IOSTREAM *s)
  263. { c &= 0xff;
  264.  
  265.   if ( s->bufp < s->limitp )
  266.     *s->bufp++ = (char)c;
  267.   else
  268.   { if ( S__flushbufc(c, s) < 0 )
  269.     { s->lastc = EOF;
  270.       return -1;
  271.     }
  272.   }
  273.   s->lastc = c;
  274.  
  275.   if ( c == '\n' && (s->flags & SIO_LBUF) )
  276.   { if ( S__flushbuf(s) < 0 )
  277.       return -1;
  278.   }
  279.  
  280.   return S__updatefilepos(s, c);
  281. }
  282.  
  283.  
  284. int
  285. Sfgetc(IOSTREAM *s)
  286. { int c;
  287.  
  288.   if ( s->bufp < s->limitp )
  289.     c = (int) *s->bufp++ & 0xff;
  290.   else
  291.     c = S__fillbuf(s);
  292.  
  293.   return S__updatefilepos(s, c);
  294. }
  295.  
  296.  
  297. int
  298. Sungetc(int c, IOSTREAM *s)
  299. { if ( s->bufp > s->unbuffer )
  300.   { *--s->bufp = c;
  301.     return c;
  302.   }
  303.  
  304.   return -1;                /* no room */
  305. }
  306.  
  307.          /*******************************
  308.          *        PUTW/GETW        *
  309.          *******************************/
  310.  
  311. int
  312. Sputw(int w, IOSTREAM *s)
  313. { unsigned char *q = (unsigned char *)&w;
  314.   int n;
  315.  
  316.   for(n=0; n<sizeof(w); n++)
  317.   { if ( Sputc(*q++, s) < 0 )
  318.       return -1;
  319.   }
  320.  
  321.   return w;
  322. }
  323.  
  324.  
  325. int
  326. Sgetw(IOSTREAM *s)
  327. { int w;
  328.   unsigned char *q = (unsigned char *)&w;
  329.   int n;
  330.  
  331.   for(n=0; n<sizeof(w); n++)
  332.   { int c;
  333.  
  334.     if ( (c = Sgetc(s)) < 0 )
  335.       return -1;
  336.     *q++ = c & 0xff;
  337.   }
  338.  
  339.   return w;
  340. }
  341.  
  342.          /*******************************
  343.          *        FREAD/FWRITE    *
  344.          *******************************/
  345.  
  346. int
  347. Sfread(void *data, int size, int elms, IOSTREAM *s)
  348. { int chars = size * elms;
  349.   char *buf = data;
  350.  
  351.   for( ; chars > 0; chars-- )
  352.   { int c;
  353.  
  354.     if ( (c = Sgetc(s)) == EOF )
  355.       break;
  356.  
  357.     *buf++ = c & 0xff;
  358.   }
  359.   
  360.   return chars ? elms : (elms - (chars+size-1)/size);
  361. }
  362.  
  363.  
  364. int
  365. Sfwrite(void *data, int size, int elms, IOSTREAM *s)
  366. { int chars = size * elms;
  367.   char *buf = data;
  368.  
  369.   for( ; chars > 0; chars-- )
  370.     if ( Sputc(*buf++, s) < 0 )
  371.       break;
  372.   
  373.   return chars ? elms : (elms - (chars+size-1)/size);
  374. }
  375.  
  376.  
  377.          /*******************************
  378.          *               FLAGS        *
  379.          *******************************/
  380.  
  381. int
  382. Sfeof(IOSTREAM *s)
  383. { return (s->flags & SIO_FEOF) != 0;
  384. }
  385.     
  386.  
  387. int
  388. Sferror(IOSTREAM *s)
  389. { return (s->flags & SIO_FERR) != 0;
  390. }
  391.     
  392.  
  393. int
  394. Sfpasteof(IOSTREAM *s)
  395. { return (s->flags & (SIO_FEOF2ERR|SIO_FEOF2)) == (SIO_FEOF2ERR|SIO_FEOF2);
  396. }
  397.  
  398.  
  399. void
  400. Sclearerr(IOSTREAM *s)
  401. { s->flags &= ~(SIO_FEOF|SIO_FERR|SIO_FEOF2);
  402. }
  403.  
  404.  
  405.          /*******************************
  406.          *          FLUSH        *
  407.          *******************************/
  408.  
  409. int
  410. Sflush(IOSTREAM *s)
  411. { if ( s->buffer && (s->flags & SIO_OUTPUT) )
  412.     return S__flushbuf(s);
  413.  
  414.   return 0;
  415. }
  416.  
  417.          /*******************************
  418.          *          SEEK        *
  419.          *******************************/
  420.  
  421. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  422. Maybe we should optimise this to become block-aligned?  Or can we leave
  423. this to read/write?
  424. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  425.  
  426. long
  427. Sseek(IOSTREAM *s, long pos, int whence)
  428. { if ( !s->functions->seek )
  429.   { errno = ESPIPE;
  430.     return -1;
  431.   }
  432.  
  433.   Sflush(s);
  434.     
  435.   s->bufp   = s->buffer;
  436.   s->limitp = s->buffer;
  437.   s->flags &= ~SIO_FEOF;        /* not on eof of file anymore */
  438.  
  439.   if ( whence == SIO_SEEK_CUR )
  440.   { pos += Stell(s);
  441.     whence = SIO_SEEK_SET;
  442.   }
  443.   pos = (*s->functions->seek)(s->handle, pos, whence);
  444.  
  445.   if ( s->position )
  446.   { s->flags |= (SIO_NOLINENO|SIO_NOLINEPOS); /* no update this */
  447.     s->position->charno = pos;
  448.   }
  449.  
  450.   return pos;
  451. }
  452.  
  453.  
  454. long
  455. Stell(IOSTREAM *s)
  456. { if ( s->position )
  457.   { return s->position->charno;
  458.   } else if ( s->functions->seek )
  459.   { long pos = (*s->functions->seek)(s->handle, 0L, SIO_SEEK_CUR);
  460.  
  461.     if ( s->buffer )            /* open */
  462.     { if ( s->flags & SIO_INPUT )
  463.       { pos -= s->limitp - s->buffer;
  464.     pos += s->bufp - s->buffer;
  465.       } else
  466.       { pos += s->bufp - s->buffer;
  467.       }
  468.     }
  469.  
  470.     return pos;
  471.   } else
  472.   { errno = EINVAL;
  473.     return -1;
  474.   }
  475. }
  476.  
  477.  
  478.          /*******************************
  479.          *          CLOSE        *
  480.          *******************************/
  481.  
  482. int
  483. Sclose(IOSTREAM *s)
  484. { int rval = 0;
  485.  
  486.   if ( s->buffer )
  487.   { if ( (s->flags & SIO_OUTPUT) && S__flushbuf(s) < 0 )
  488.       rval = -1;
  489.  
  490.     if ( !(s->flags & SIO_USERBUF) )
  491.       free(s->buffer);
  492.  
  493.     s->buffer = NULL;
  494.   }
  495.  
  496.   if ( s->functions->close && (*s->functions->close)(s->handle) < 0 )
  497.     rval = -1;
  498.  
  499.   s->magic = 0;
  500.   if ( !(s->flags & SIO_STATIC) )
  501.     free(s);
  502.  
  503.   return rval;
  504. }
  505.  
  506.  
  507.          /*******************************
  508.          *         STRING I/O        *
  509.          *******************************/
  510.  
  511. char *
  512. Sfgets(char *buf, int n, IOSTREAM *s)
  513. { char *q = buf;
  514.  
  515.   while( n-- > 0 )
  516.   { int c = Sgetc(s);
  517.  
  518.     if ( c == EOF )
  519.     { *q = '\0';
  520.       if ( q > buf )
  521.     return buf;
  522.       else
  523.     return NULL;
  524.     } else
  525.     { *q++ = c;
  526.       if ( c == '\n' )
  527.       { if ( n > 0 )
  528.       *q = '\0';
  529.     return buf;
  530.       }
  531.     }
  532.   }
  533.  
  534.   return buf;
  535. }
  536.  
  537.  
  538. char *
  539. Sgets(char *buf)
  540. { char *s = Sfgets(buf, Slinesize, Sinput);
  541.   char *q;
  542.  
  543.   if ( s )                /* delete trailing \n */
  544.   { q = &s[strlen(s)];
  545.     if ( q > s && q[-1] == '\n' )
  546.       *--q = '\0';
  547.   }
  548.  
  549.   return s;
  550. }
  551.  
  552.  
  553. int
  554. Sfputs(const char *q, IOSTREAM *s)
  555. { for( ; *q; q++)
  556.   { if ( Sputc(*q, s) < 0 )
  557.       return EOF;
  558.   }
  559.  
  560.   return 0;
  561. }
  562.  
  563.  
  564. int
  565. Sputs(const char *q)
  566. { return Sfputs(q, Soutput);
  567. }
  568.  
  569.  
  570.          /*******************************
  571.          *           PRINTF        *
  572.          *******************************/
  573.  
  574. int
  575. Sfprintf(IOSTREAM *s, const char *fm, ...)
  576. { va_list args;
  577.   int rval;
  578.  
  579.   va_start(args, fm);
  580.   rval = Svfprintf(s, fm, args);
  581.   va_end(args);
  582.  
  583.   return rval;
  584. }
  585.  
  586.  
  587. int
  588. Sprintf(const char *fm, ...)
  589. { va_list args;
  590.   int rval;
  591.  
  592.   va_start(args, fm);
  593.   rval = Svfprintf(Soutput, fm, args);
  594.   va_end(args);
  595.  
  596.   return rval;
  597. }
  598.  
  599.  
  600. int
  601. Svprintf(const char *fm, va_list args)
  602. { return Svfprintf(Soutput, fm, args);
  603. }
  604.  
  605.  
  606. #define OUT(s, c)    do { printed++; \
  607.                  if ( Sputc((c), (s)) < 0 ) return -1; \
  608.                } while(0)
  609. #define valdigit(c)    ((c) - '0')
  610. #define A_LEFT    0            /* left-aligned field */
  611. #define A_RIGHT 1            /* right-aligned field */
  612.  
  613. int
  614. Svfprintf(IOSTREAM *s, const char *fm, va_list args)
  615. { long printed = 0;
  616.   char buf[TMPBUFSIZE];
  617.   int tmpbuf;
  618.  
  619.   if ( !s->buffer && (s->flags & SIO_NBUF) )
  620.   { S__setbuf(s, buf, sizeof(buf));
  621.     tmpbuf = TRUE;
  622.   } else
  623.     tmpbuf = FALSE;
  624.  
  625.   while(*fm)
  626.   { if ( *fm == '%' )
  627.     { fm++;
  628.  
  629.       if ( *fm == '%' )
  630.       { OUT(s, *fm);
  631.     fm++;
  632.     continue;
  633.       } else
  634.       { int align = A_RIGHT;
  635.     int modified = FALSE;
  636.     int has_arg1 = FALSE, has_arg2 = FALSE;
  637.     int arg1=0, arg2=0;
  638.     char fbuf[100], *fs = fbuf, *fe = fbuf;
  639.     int islong = FALSE;
  640.     int pad = ' ';
  641.  
  642.     for(;;)
  643.     { switch(*fm)
  644.       { case '+':    align = A_RIGHT; fm++; continue;
  645.         case '-':    align = A_LEFT;  fm++; continue;
  646.         case '0':    pad = '0';     fm++; continue;
  647.         case ' ':    pad = ' ';       fm++; continue;
  648.         case '#':   modified = TRUE; fm++; continue;
  649.       }
  650.       break;
  651.     }
  652.  
  653.     if ( *fm == '*' )
  654.     { has_arg1++;
  655.       arg1 = va_arg(args, int);
  656.     } else if ( isdigit(*fm) )
  657.     { if ( *fm == '0' )
  658.         pad = '0';
  659.       arg1 = valdigit(*fm);
  660.       has_arg1++;
  661.       for( fm++; isdigit(*fm); fm++)
  662.         arg1 = arg1*10 + valdigit(*fm);
  663.     }
  664.     if ( *fm == '.' )
  665.     { has_arg2++;
  666.       fm++;
  667.       if ( *fm == '*' )
  668.       { arg2 = va_arg(args, int);
  669.       } else
  670.       { arg2 = 0;
  671.         for( ; isdigit(*fm); fm++)
  672.           arg2 = arg2*10 + valdigit(*fm);
  673.       }
  674.     }
  675.  
  676.     if ( *fm == 'l' )
  677.     { islong++;
  678.       fm++;
  679.     }
  680.  
  681.     switch(*fm)
  682.     { case 'c':
  683.         *fe++ = va_arg(args, int);
  684.         break;
  685.       case 'd':
  686.       case 'p':
  687.       case 'i':
  688.       case 'o':
  689.       case 'u':
  690.       case 'x':
  691.       case 'X':
  692.       { long v;
  693.         char fmbuf[8], *fp=fmbuf;
  694.  
  695.         if ( islong )
  696.           v = va_arg(args, long);
  697.         else
  698.           v = va_arg(args, int);
  699.  
  700.         *fp++ = '%';
  701.         if ( modified )
  702.           *fp++ = '#';
  703.         *fp++ = 'l';
  704.         *fp++ = *fm;
  705.         *fp   = '\0';
  706.         sprintf(fs, fmbuf, v);
  707.         fe = &fs[strlen(fs)];
  708.  
  709.         break;
  710.       }
  711.       case 'f':
  712.       case 'e':
  713.       case 'E':
  714.       case 'g':
  715.       case 'G':
  716.       { double v = va_arg(args, double);
  717.         char fmbuf[8], *fp=fmbuf;
  718.  
  719.         *fp++ = '%';
  720.         if ( modified )
  721.           *fp++ = '#';
  722.         if ( has_arg2 )        /* specified percission */
  723.         { *fp++ = '.';
  724.           *fp++ = '*';
  725.           *fp++ = *fm;
  726.           *fp   = '\0';
  727.           sprintf(fs, fmbuf, arg2, v);
  728.         } else
  729.         { *fp++ = *fm;
  730.           *fp   = '\0';
  731.           sprintf(fs, fmbuf, v);
  732.         }
  733.         fe = &fs[strlen(fs)];
  734.  
  735.         break;
  736.       }
  737.       case 's':
  738.         fs = va_arg(args, char *);
  739.         break;
  740.     }
  741.  
  742.     if ( has_arg1 )            /* aligned field */
  743.     { if ( fs == fbuf )
  744.         *fe = '\0';
  745.  
  746.       if ( align == A_LEFT )
  747.       { int w = 0;
  748.         while(*fs)
  749.         { OUT(s, *fs++);
  750.           w++;
  751.         }
  752.         while(w < arg1)
  753.         { OUT(s, pad);
  754.           w++;
  755.         }
  756.       } else /*if ( align == A_RIGHT ) */
  757.       { int w;
  758.  
  759.         if ( fs == fbuf )
  760.           w = fe - fs;
  761.         else
  762.           w = strlen(fs);
  763.  
  764.         w = arg1 - w;
  765.         while(w > 0 )
  766.         { OUT(s, pad);
  767.           w--;
  768.         }
  769.         while(*fs)
  770.           OUT(s, *fs++);
  771.       }
  772.     } else
  773.     { if ( fs == fbuf )        /* unaligned field, just output */
  774.       { while(fs < fe)
  775.           OUT(s, *fs++);
  776.       } else
  777.       { while(*fs)
  778.           OUT(s, *fs++);
  779.       }
  780.     }
  781.     fm++;
  782.       }
  783.     } else
  784.     { OUT(s, *fm);
  785.       fm++;
  786.     }
  787.   }
  788.  
  789.   if ( tmpbuf )
  790.   { if ( S__removebuf(s) < 0 )
  791.       return -1;
  792.   }
  793.  
  794.   return printed;
  795. }
  796.  
  797.  
  798. int
  799. Ssprintf(char *buf, const char *fm, ...)
  800. { va_list args;
  801.   int rval;
  802.  
  803.   va_start(args, fm);
  804.   rval = Svsprintf(buf, fm, args);
  805.   va_end(args);
  806.  
  807.   return rval;
  808. }
  809.  
  810.  
  811. int
  812. Svsprintf(char *buf, const char *fm, va_list args)
  813. { IOSTREAM s;
  814.   int rval;
  815.  
  816.   s.bufp      = buf;
  817.   s.limitp    = (char *)(~0L);
  818.   s.buffer    = buf;
  819.   s.flags     = SIO_FBUF|SIO_OUTPUT;
  820.   s.position  = NULL;
  821.   s.handle    = NULL;
  822.   s.functions = NULL;
  823.   
  824.   if ( (rval = Svfprintf(&s, fm, args)) >= 0 )
  825.     *s.bufp = '\0';
  826.  
  827.   return rval;
  828. }
  829.  
  830.  
  831. int
  832. Svdprintf(const char *fm, va_list args)
  833. { int rval;
  834.  
  835.   rval = Svfprintf(Soutput, fm, args);
  836.   Sflush(Soutput);
  837.  
  838.   return rval;
  839. }
  840.  
  841.  
  842. int
  843. Sdprintf(const char *fm, ...)
  844. { va_list args;
  845.   int rval;
  846.  
  847.   va_start(args, fm);
  848.   rval = Svdprintf(fm, args);
  849.   va_end(args);
  850.  
  851.   return rval;
  852. }
  853.  
  854. #if 0
  855.          /*******************************
  856.          *          SCANF        *
  857.          *******************************/
  858.  
  859. int
  860. Svfscanf(IOSTREAM *s, const char *fm, va_list args)
  861. { int done = 0;                /* # items converted */
  862.   int chread = 0;            /* # characters read */
  863.   int c = GET(s);            /* current character */
  864.   int supress;                /* if TRUE, don't assign (*) */
  865.   int field_width;            /* max width of field */
  866.   int tsize;                /* SZ_SHORT, SZ_NORMAL, SZ_LONG */
  867.  
  868.   while(*fm)
  869.   { if ( *fm == ' ' )
  870.     { while ( isblank(c) )
  871.     c = GET(s);
  872.       fm++;
  873.       continue;
  874.     } else if ( *fm == '%' && fm[1] != '%' )
  875.     { supress = FALSE;
  876.       field_width = -1;
  877.       int size = SZ_STANDARD;
  878.  
  879.       for(;;)                /* parse modifiers */
  880.       { fm++;
  881.     if ( isdigit(*fm) )
  882.     { field_width = valdigit(*fm);
  883.       for(++fm; isdigit(*fm); fm++)
  884.         field_width = 10*field_width + valdigit(*fm);
  885.       fm--;
  886.       continue;
  887.     }
  888.     if ( *fm == '*' )
  889.     { supress++;
  890.       continue;
  891.     }
  892.     if ( *fm == 'l' )
  893.     { size = SZ_LONG;
  894.       continue;
  895.     }
  896.     if ( *fm == 'h' )
  897.     { size = SZ_SHORT;
  898.       continue;
  899.     }
  900.       }
  901.     
  902.       if ( *fm != '[' && *fm != c )
  903.     while(isblank(c))
  904.       c = GET(s);
  905.  
  906.       switch(*fm)
  907.       { { long v;            /* collect value here */
  908.       int negative;            /* true if < 0 */
  909.       int base;            /* base for conversion */
  910.       int ok;            /* successful */
  911.     case 'd':
  912.       base = 10;
  913.  
  914.     do_int:
  915.       negative = FALSE;
  916.       if ( c == '+' )
  917.         c = GET(s);
  918.       else if ( c == '-' )
  919.       { negative++;
  920.         c = GET(s);
  921.       }
  922.     do_unsigned:
  923.       ok = FALSE;
  924.       if ( base == 16 )        /* hexadecimal */
  925.       { if ( isxdigit(c) )
  926.         { v = valxdigit(c);
  927.           for(c = GET(s); isxdigit(c); c = GET(s))
  928.         v = base*v + valxdigit(c);
  929.           ok++;
  930.         }
  931.       } else
  932.       { int cv;
  933.  
  934.         if ( isdigit(c) && (cv=valdigit(c)) < base )
  935.         { v = cv;
  936.           for(c = GET(s); isdigit(c) && (cv=valdigit(c)) < base; c = GET(s))
  937.         v = base*v + cv;
  938.           ok++;
  939.         }
  940.       }
  941.  
  942.       if ( ok )
  943.       { if ( !supress )
  944.         { if ( negative )
  945.         v = -v;
  946.           if ( tsize == SZ_SHORT )
  947.           { short *vp = va_arg(args, short *);
  948.         *vp = v;
  949.           } else if ( tsize == SZ_LONG )
  950.           { long *vp = va_arg(args, long *);
  951.         *vp = v;
  952.           } else
  953.           { int *vp = va_arg(args, int *);
  954.         *vp = v;
  955.           }
  956.           done++;
  957.         }
  958.         continue;            /* with next */
  959.       } else
  960.         return done;
  961.     case 'u':
  962.       base = 10;
  963.       negative = FALSE;
  964.       goto do_unsigned;
  965.     case 'o':
  966.       base = 8;
  967.       goto do_int;
  968.     case 'x':
  969.       base = 16;
  970.       goto do_int;
  971.     case 'i':
  972.       if ( c == '0' )
  973.       { int c2 = GET(s);
  974.  
  975.         if ( c2 == 'x' )
  976.         { base = 16;
  977.           c = GET(s);
  978.         } else
  979.         { UNGET(c2, s);
  980.           base = 8;
  981.         }
  982.         negative = FALSE;
  983.         goto do_unsigned;
  984.       }
  985.       base = 10;
  986.       goto do_int;
  987.     }
  988.     case 'n':
  989.       if ( !supress )
  990.       { if ( tsize == SZ_SHORT )
  991.         { short *vp = va_arg(args, short *);
  992.           *vp = chread;
  993.         } else if ( tsize == SZ_LONG )
  994.         { long *vp = va_arg(args, long *);
  995.           *vp = chread;
  996.         } else
  997.         { int *vp = va_arg(args, int *);
  998.           *vp = chread;
  999.         }
  1000.         done++;
  1001.       }
  1002.       fm++;
  1003.       continue;
  1004.     case 'E':
  1005.     case 'e':
  1006.     case 'f':
  1007.     case 'G':
  1008.     case 'g':
  1009.     { char work[200];
  1010.       char *w = work;
  1011.       int ds = 0;
  1012.       double v;
  1013.  
  1014.       if ( c == '-' || c == '+' )    /* [+|-] */
  1015.       { *w++ = c;
  1016.         c = GET(s);
  1017.       }
  1018.       while(isdigit(c))        /* {digit} */
  1019.       { *w++ = c;
  1020.         c = GET(s);
  1021.         ds++;
  1022.       }
  1023.       if ( c == '.' )        /* [.] */
  1024.         *w++ = c;
  1025.       while(isdigit(c))        /* {digit} */
  1026.       { *w++ = c;
  1027.         c = GET(s);
  1028.         ds++;
  1029.       }
  1030.       if ( !ds )
  1031.         SCAN_ERROR(s)
  1032.       if ( c == 'e' || c == 'E' )    /* [e<digit>{<digit>}] */
  1033.       { *w++ = c;
  1034.         c = GET(s);
  1035.         if ( !isdigit(c) )
  1036.           SCAN_ERROR(s)
  1037.         while(isdigit(c))
  1038.         { *w++ = c;
  1039.         c = GET(s);
  1040.         }
  1041.       }
  1042.  
  1043.       if ( !supress )
  1044.       { *w = '\0';
  1045.         v = strtod(work, &w)
  1046.         if ( w == work )
  1047.           SCAN_ERROR(s);
  1048.  
  1049.         switch(tsize)
  1050.         { case SZ_NORMAL:
  1051.           { float *fp = va_arg(args, float *);
  1052.         *fp = v;
  1053.         break;
  1054.           }    
  1055.           case SZ_LONG:
  1056.           { double *fp = va_arg(args, double *);
  1057.         *fp = v;
  1058.         break;
  1059.           }
  1060.         }  
  1061.         done++;
  1062.       }
  1063.  
  1064.       fm++;
  1065.       continue;
  1066.     }
  1067.     case 's':
  1068.       if ( !supress )
  1069.       { char *sp = va_arg(args, char *);
  1070.         
  1071.         while(!isblank(c) && field_width-- != 0)
  1072.         { *sp++ = c;
  1073.           c = GET(s);
  1074.         }
  1075.       } else
  1076.         while(!isblank(c) && field_width-- != 0)
  1077.           c = GET(s);
  1078.       fm++;
  1079.       continue;
  1080.     case 'c':
  1081.       if ( !supress )
  1082.       { char *cp = va_arg(args, char *);
  1083.         *cp = c;
  1084.       }
  1085.       c = GET(s);
  1086.       fm++;
  1087.       continue;
  1088.     case '[':
  1089.     { char set[256];
  1090.       
  1091.       memset(set, 0, sizeof(set));
  1092.       fm++;
  1093.       if ( *fm == ']' )
  1094.         set[*fm++]++;
  1095.       else if ( *fm == '^' )
  1096.       { fm++;
  1097.         negate++;
  1098.       }
  1099.       while(*fm != ']')
  1100.       { if ( *fm == '-' )
  1101.           
  1102.       }
  1103.     }
  1104.       }
  1105.     } else                /* normal character */
  1106.     { if ( c == *fm )
  1107.       { c = GET(s);
  1108.     fm++;
  1109.     continue;
  1110.       }
  1111.  
  1112.       break;
  1113.     }
  1114.   }
  1115.  
  1116. out:
  1117.   UNGET(c, s);
  1118.  
  1119.   return done;
  1120. }
  1121.  
  1122. #endif /*0*/
  1123.  
  1124.  
  1125.  
  1126.          /*******************************
  1127.          *        FILE STREAMS    *
  1128.          *******************************/
  1129.  
  1130. static int
  1131. Sread_file(void *handle, char *buf, int size)
  1132. { long h = (long) handle;
  1133.  
  1134.   return read((int)h, buf, size);
  1135. }
  1136.  
  1137.  
  1138. static int
  1139. Swrite_file(void *handle, char *buf, int size)
  1140. { long h = (long) handle;
  1141.  
  1142.   return write((int)h, buf, size);
  1143. }
  1144.  
  1145.  
  1146. static long
  1147. Sseek_file(void *handle, long pos, int whence)
  1148. { long h = (long) handle;
  1149.  
  1150.   return lseek((int)h, pos, whence);
  1151. }
  1152.  
  1153.  
  1154. static int
  1155. Sclose_file(void *handle)
  1156. { long h = (long) handle;
  1157.  
  1158.   return close((int) h);
  1159. }
  1160.  
  1161.  
  1162. IOFUNCTIONS Sfilefunctions =
  1163. { Sread_file,
  1164.   Swrite_file,
  1165.   Sseek_file,
  1166.   Sclose_file
  1167. };
  1168.  
  1169.  
  1170. IOSTREAM *
  1171. Snew(void *handle, int flags, IOFUNCTIONS *functions)
  1172. { IOSTREAM *s;
  1173.  
  1174.   if ( !(s = malloc(sizeof(IOSTREAM))) )
  1175.   { errno = ENOMEM;
  1176.     return NULL;
  1177.   }
  1178.   memset((char *)s, 0, sizeof(IOSTREAM));
  1179.   s->magic     = SIO_MAGIC;
  1180.   s->lastc     = EOF;
  1181.   s->flags     = flags;
  1182.   s->handle    = handle;
  1183.   s->functions = functions;
  1184.   if ( flags & SIO_RECORDPOS )
  1185.   { s->position = &s->posbuf;
  1186.     s->posbuf.lineno = 1;
  1187.   }
  1188.  
  1189.   return s;
  1190. }
  1191.  
  1192.  
  1193. #ifndef O_BINARY
  1194. #define O_BINARY 0
  1195. #endif
  1196.  
  1197. IOSTREAM *
  1198. Sopen_file(const char *path, char *how)
  1199. { int fd;
  1200.   int oflags = 0, flags = SIO_FILE|SIO_TEXT|SIO_RECORDPOS;
  1201.   int op = *how++;
  1202.   long lfd;
  1203.  
  1204.   for( ; *how; how++)
  1205.   { switch(*how)
  1206.     { case 'b':                /* binary */
  1207.     flags &= ~SIO_TEXT;
  1208.         oflags = O_BINARY;
  1209.         break;
  1210.       case 'r':                /* no record */
  1211.     flags &= SIO_RECORDPOS;
  1212.         break;
  1213.       default:
  1214.     errno = EINVAL;
  1215.         return NULL;
  1216.     }
  1217.   }
  1218.  
  1219.   switch(op)
  1220.   { case 'w':
  1221.       fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|oflags, 0666);
  1222.       flags |= SIO_OUTPUT;
  1223.       break;
  1224.     case 'a':
  1225.       fd = open(path, O_WRONLY|O_CREAT|O_APPEND|oflags, 0666);
  1226.       flags |= SIO_OUTPUT;
  1227.       break;
  1228.     case 'u':
  1229.       fd = open(path, O_WRONLY|O_CREAT|oflags, 0666);
  1230.       flags |= SIO_OUTPUT;
  1231.       break;
  1232.     case 'r':
  1233.       fd = open(path, O_RDONLY|oflags);
  1234.       flags |= SIO_INPUT;
  1235.       break;
  1236.     default:
  1237.       errno = EINVAL;
  1238.       return NULL;
  1239.   }
  1240.  
  1241.   if ( fd < 0 )
  1242.     return NULL;
  1243.  
  1244.   lfd = (long)fd;
  1245.   return Snew((void *)lfd, flags, &Sfilefunctions);
  1246. }
  1247.  
  1248.  
  1249. IOSTREAM *
  1250. Sfdopen(int fd, char *type)
  1251. { int flags;
  1252.   long lfd;
  1253.  
  1254.   if ( fd < 0 )
  1255.     return NULL;
  1256.  
  1257.   if ( *type == 'r' )
  1258.     flags = SIO_FILE|SIO_INPUT;
  1259.   else
  1260.     flags = SIO_FILE|SIO_OUTPUT;
  1261.  
  1262.   lfd = (long)fd;
  1263.  
  1264.   return Snew((void *)lfd, flags, &Sfilefunctions);
  1265. }
  1266.  
  1267.  
  1268. int
  1269. Sfileno(IOSTREAM *s)
  1270. { if ( s->flags & SIO_FILE )
  1271.   { long h = (long)s->handle;
  1272.     return (int)h;
  1273.   }
  1274.   if ( s->flags & SIO_PIPE )
  1275.     return fileno((FILE *)s->handle);
  1276.  
  1277.   errno = EINVAL;
  1278.   return -1;                /* no file stream */
  1279. }
  1280.  
  1281.  
  1282. #define STDIO(n, f) { NULL, NULL, NULL, NULL, \
  1283.               SIO_MAGIC, EOF, 0, f, {0, 0, 0}, NULL, \
  1284.               ((void *)(n)), &Sfilefunctions \
  1285.             }
  1286.  
  1287. IOSTREAM S__iob[] =
  1288. #define SIO_STDIO (SIO_FILE|SIO_STATIC|SIO_NOCLOSE)
  1289.   STDIO(0, SIO_STDIO|SIO_LBUF|SIO_INPUT|SIO_NOFEOF),    /* Sinput */
  1290.   STDIO(1, SIO_STDIO|SIO_LBUF|SIO_OUTPUT),         /* Soutput */
  1291.   STDIO(2, SIO_STDIO|SIO_NBUF|SIO_OUTPUT)        /* Serror */
  1292. };
  1293.  
  1294.  
  1295. IOSTREAM *
  1296. S__getiob()
  1297. { return S__iob;
  1298. }
  1299.  
  1300.          /*******************************
  1301.          *           PIPES        *
  1302.          *******************************/
  1303.  
  1304. #ifdef HAVE_POPEN
  1305.  
  1306. static int
  1307. Sread_pipe(void *handle, char *buf, int size)
  1308. { FILE *fp = handle;
  1309.  
  1310.   return read(fileno(fp), buf, size);
  1311. }
  1312.  
  1313.  
  1314. static int
  1315. Swrite_pipe(void *handle, char *buf, int size)
  1316. { FILE *fp = handle;
  1317.  
  1318.   return write(fileno(fp), buf, size);
  1319. }
  1320.  
  1321.  
  1322. static int
  1323. Sclose_pipe(void *handle)
  1324. { FILE *fp = handle;
  1325.  
  1326.   pclose(fp);
  1327.   return 0;
  1328. }
  1329.  
  1330.  
  1331. IOFUNCTIONS Spipefunctions =
  1332. { Sread_pipe,
  1333.   Swrite_pipe,
  1334.   NULL,
  1335.   Sclose_pipe
  1336. };
  1337.  
  1338.  
  1339. IOSTREAM *
  1340. Sopen_pipe(const char *command, const char *type)
  1341. { FILE *fd = popen(command, type);    /* HACK for now */
  1342.  
  1343.   if ( fd )
  1344.   { int flags;
  1345.  
  1346.     if ( *type == 'r' )
  1347.       flags = SIO_PIPE|SIO_INPUT;
  1348.     else
  1349.       flags = SIO_PIPE|SIO_OUTPUT;
  1350.  
  1351.     return Snew((void *)fd, flags, &Spipefunctions);
  1352.   }
  1353.  
  1354.   return NULL;
  1355. }
  1356.  
  1357. #endif /*HAVE_POPEN*/
  1358.  
  1359.          /*******************************
  1360.          *      MEMORY STREAMS    *
  1361.          *******************************/
  1362.  
  1363. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1364. Memory streams form a replacement for   sprintf(), sscanf() and friends.
  1365. They allow regarding a piece of  (for output) malloc() maintained memory
  1366. to serve as a temporary buffer.
  1367. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  1368.  
  1369. typedef struct
  1370. { long    here;                /* `here' location */
  1371.   long  size;                /* size of buffer */
  1372.   int  *sizep;                /* pointer to size */
  1373.   long    allocated;            /* allocated size */
  1374.   char **buffer;            /* allocated buffer */
  1375.   int    malloced;            /* malloc() maintained */
  1376. } memfile;
  1377.  
  1378.  
  1379. static int
  1380. S__memfile_nextsize(int needed)
  1381. { needed += needed/4;
  1382.  
  1383.   return (needed + 255) & ~255;
  1384. }
  1385.  
  1386.  
  1387. static int
  1388. Swrite_memfile(void *handle, char *buf, int size)
  1389. { memfile *mf = handle;
  1390.  
  1391.   if ( mf->here + size + 1 >= mf->allocated )
  1392.   { long ns = S__memfile_nextsize(mf->here + size);
  1393.     char *nb;
  1394.  
  1395.     if ( mf->allocated == 0 || !mf->malloced )
  1396.     { if ( !(nb = malloc(ns)) )
  1397.       { errno = ENOMEM;
  1398.     return -1;
  1399.       }
  1400.       if ( !mf->malloced )
  1401.       { if ( *mf->buffer )
  1402.       memcpy(nb, *mf->buffer, mf->allocated);
  1403.     mf->malloced = TRUE;
  1404.       }
  1405.     } else
  1406.     { if ( !(nb = realloc(*mf->buffer, ns)) )
  1407.       { errno = ENOMEM;
  1408.     return -1;
  1409.       }
  1410.     }
  1411.  
  1412.     mf->allocated = ns;
  1413.     *mf->buffer = nb;
  1414.   }
  1415.  
  1416.   memcpy(&(*mf->buffer)[mf->here], buf, size);
  1417.   mf->here += size;
  1418.  
  1419.   if ( mf->here > mf->size )
  1420.   { mf->size = mf->here;
  1421.     if ( mf->sizep )            /* make externally known */
  1422.       *mf->sizep = mf->size;
  1423.     (*mf->buffer)[mf->size] = '\0';
  1424.   }
  1425.  
  1426.   return size;
  1427. }
  1428.  
  1429.  
  1430. static int
  1431. Sread_memfile(void *handle, char *buf, int size)
  1432. { memfile *mf = handle;
  1433.  
  1434.   if ( size + mf->here > mf->size )
  1435.   { size = mf->size - mf->here;
  1436.     if ( size < 0 )
  1437.       size = 0;
  1438.   }
  1439.   
  1440.   memcpy(buf, &(*mf->buffer)[mf->here], size);
  1441.   mf->here += size;
  1442.  
  1443.   return size;
  1444. }
  1445.  
  1446.  
  1447. static long
  1448. Sseek_memfile(void *handle, long offset, int whence)
  1449. { memfile *mf = handle;
  1450.  
  1451.   switch(whence)
  1452.   { case SIO_SEEK_SET:
  1453.       break;
  1454.     case SIO_SEEK_CUR:
  1455.       offset += mf->here;
  1456.       break;
  1457.     case SIO_SEEK_END:
  1458.       offset = mf->size - offset;
  1459.       break;
  1460.     default:
  1461.       errno = EINVAL;
  1462.       return -1;
  1463.   }
  1464.   if ( offset < 0 || offset > mf->size )
  1465.   { errno = EINVAL;
  1466.     return -1;
  1467.   }
  1468.   mf->here = offset;
  1469.  
  1470.   return offset;
  1471. }
  1472.  
  1473.  
  1474. static int
  1475. Sclose_memfile(void *handle)
  1476. { memfile *mf = handle;
  1477.  
  1478.   if ( mf )
  1479.   { free(mf);
  1480.     return 0;
  1481.   }
  1482.      
  1483.   errno = EINVAL;            /* not opened */
  1484.   return -1;
  1485. }
  1486.  
  1487.  
  1488. IOFUNCTIONS Smemfunctions =
  1489. { Sread_memfile,
  1490.   Swrite_memfile,
  1491.   Sseek_memfile,
  1492.   Sclose_memfile
  1493. };
  1494.  
  1495.  
  1496. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1497. Sopenmem(char **buffer, int *size, char* mode)
  1498.     Open an memory area as a stream.  Output streams will automatically
  1499.     resized using realloc() if *size = 0 or the stream is opened with mode
  1500.     "wa".
  1501. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  1502.  
  1503. IOSTREAM *
  1504. Sopenmem(char **buffer, int *sizep, const char *mode)
  1505. { memfile *mf = malloc(sizeof(memfile));
  1506.   int flags = SIO_FBUF;
  1507.   int size;
  1508.  
  1509.   if ( !mf )
  1510.   { errno = ENOMEM;
  1511.     return NULL;
  1512.   }
  1513.  
  1514.   mf->malloced = FALSE;
  1515.  
  1516.   switch(*mode)
  1517.   { case 'r':
  1518.       flags |= SIO_INPUT;
  1519.       if ( sizep == NULL || *sizep < 0 )
  1520.     size = (*buffer ? strlen(*buffer) : 0);
  1521.       else
  1522.     size = *sizep;
  1523.       mf->size = size;
  1524.       mf->allocated = size+1;
  1525.       break;
  1526.     case 'w':
  1527.       flags |= SIO_OUTPUT;
  1528.       mf->size = 0;
  1529.       mf->allocated = (sizep ? *sizep : 0);
  1530.       if ( *buffer == NULL || mode[1] == 'a' )
  1531.     mf->malloced = TRUE;
  1532.       if ( *buffer )
  1533.     *buffer[0] = '\0';
  1534.       break;
  1535.     default:
  1536.       free(mf);
  1537.       errno = EINVAL;
  1538.       return NULL;
  1539.   }
  1540.  
  1541.   mf->sizep    = sizep;
  1542.   mf->here      = 0;
  1543.   mf->buffer    = buffer;
  1544.  
  1545.   return Snew(mf, flags, &Smemfunctions);
  1546. }
  1547.  
  1548.          /*******************************
  1549.          *          STRINGS        *
  1550.          *******************************/
  1551.  
  1552. static int
  1553. Sread_string(void *handle, char *buf, int size)
  1554. { return 0;                /* signal EOF */
  1555. }
  1556.  
  1557. static int
  1558. Swrite_string(void *handle, char *buf, int size)
  1559. { errno = ENOSPC;            /* signal error */
  1560.   return -1;
  1561. }
  1562.  
  1563. static int
  1564. Sclose_string(void *handle)
  1565. { IOSTREAM *s = handle;
  1566.  
  1567.   if ( s->flags & SIO_OUTPUT )
  1568.   { if ( s->bufp < s->limitp )
  1569.     { *s->bufp++ = '\0';
  1570.       return 0;
  1571.     } else
  1572.     { errno = ENOSPC;            /* signal error */
  1573.       return -1;
  1574.     }
  1575.   } else
  1576.     return 0;                /* input string */
  1577. }
  1578.  
  1579. IOFUNCTIONS Sstringfunctions =
  1580. { Sread_string,
  1581.   Swrite_string,
  1582.   NULL,
  1583.   Sclose_string
  1584. };
  1585.  
  1586.  
  1587. IOSTREAM *
  1588. Sopen_string(IOSTREAM *s, char *buf, int size, char *mode)
  1589. { int flags = SIO_FBUF|SIO_USERBUF;
  1590.  
  1591.   if ( !s )
  1592.   { if ( !(s = malloc(sizeof(IOSTREAM))) )
  1593.     { errno = ENOMEM;
  1594.       return NULL;
  1595.     }
  1596.   } else
  1597.     flags |= SIO_STATIC;
  1598.  
  1599.   s->buffer    = buf;
  1600.   s->bufp      = buf;
  1601.   s->unbuffer  = buf;
  1602.   s->position  = NULL;
  1603.   s->handle    = s;            /* for Sclose_string() */
  1604.   s->functions = &Sstringfunctions;
  1605.  
  1606.   switch(*mode)
  1607.   { case 'r':
  1608.       if ( size < 0 )
  1609.     size = strlen(buf);
  1610.       flags |= SIO_INPUT;
  1611.       break;
  1612.     case 'w':
  1613.       flags |= SIO_OUTPUT;
  1614.       break;
  1615.     default:
  1616.       errno = EINVAL;
  1617.       return NULL;
  1618.   }
  1619.  
  1620.   s->flags  = flags;
  1621.   s->limitp = &buf[size];
  1622.  
  1623.   return s;
  1624. }
  1625.  
  1626. #undef S__fupdatefilepos
  1627.  
  1628. int
  1629. S__fupdatefilepos(IOPOS *p, int c)
  1630. { return S___fupdatefilepos(p, c);
  1631. }
  1632.